#include "Manager.h"
#include <stack>

priority_queue<struct arrival, vector<struct arrival>, ArrivalCompare> StratManager::arrivalQueue =
	priority_queue<struct arrival, vector<struct arrival>, ArrivalCompare>();

StratManager::StratManager()
{
	NCUManager = new NonCombatUnitManager(this);
	trainingManager = new TrainingManager(this);
}

void StratManager::onUnitRequest(Request request)
{
	//Determine whether to transfer or train units.
	Broodwar->printf("%d %ss requested.\n", request.count, request.uType.getName().c_str());
	if(request.uType.canMove())
		trainingManager->trainUnits(request);
	else
		NCUManager->buildUnits(request);
}

struct LeadTime StratManager::onUnitTimeQuerry(Request request)
{
	//Calculate the time to train or transfer units
	struct LeadTime leadTime;
	return leadTime;
}

void StratManager::onStart()
{
	NCUManager->start();
	trainingManager->start();
	vzManager.start();
}

void StratManager::onStop()
{
	NCUManager->stop();
	trainingManager->stop();
}

void StratManager::onThink()
{
	NCUManager->think();
	trainingManager->think();
}

void StratManager::vzThink()
{
	vzManager.think();
}

void StratManager::addArrival(struct arrival arrival)
{
	arrivalQueue.push(arrival);
}

bool isVowel(char const letter)
{
	static char const vowels[10] ={
		'A', 'E', 'I', 'O', 'U',
		'a', 'e', 'i', 'o', 'u'
	};

	for(int i = 0; i < 10; i++)
		if(letter == vowels[i])
			return true;
	return false;
}

void StratManager::onUnitDiscover(Unit *unit)
{
	vzManager.giveUnit(unit);
}

// Handle incoming units. Add them to the propper group.
// Skip their manager if they were requested with a TrainAction.
// If they were not requested in a TrainAction their manager must
// be informed to be able to classify it into the propper group.
void StratManager::onUnitArrival(Unit *unit)
{
	stack<struct arrival> ties;
	UnitGroup *uGroup = NULL;

	// add it to the vital zones if needed
	if(unit->getPlayer() != Broodwar->self())
		return;
	for(int i = 0; i < arrivalQueue.size(); i++) {
		struct arrival top = arrivalQueue.top();
		arrivalQueue.pop();
		if(/*(top.origin == unit->getTarget() || top.origin == NULL) && */top.uType == unit->getType()) {
			uGroup = top.group;
			break;
		}
		else
			ties.push(top);
	}
	for(int i = 0; i < ties.size(); i++) {
		arrivalQueue.push(ties.top());
		ties.pop();
	}
	// if the unit was requested uGroup is no longer NULL
	char const *typeName = unit->getType().getName().c_str();
	if(uGroup) {
		Broodwar->printf("Request for a%s %s has arrived.", (isVowel(typeName[0]) ? "n":""), typeName);
		uGroup->addUnit(unit);
		trainingManager->giveUnit(unit, true);
		NCUManager->giveUnit(unit, true);
	}
	else {
		// Tell the managers to classify this unit
		// They do not have to place them in a group, but units can be in multiple groups.
		//Broodwar->printf("Categorizing a%s %s", (isVowel(typeName[0]) ? "n":""), typeName);
		trainingManager->giveUnit(unit,false);
		NCUManager->giveUnit(unit,false);
	}
}

StratManager::~StratManager()
{
	delete NCUManager;
	delete trainingManager;
}